﻿using System.Collections.Generic;
using Batman.Core;
using IdentityServer4.EntityFramework.DbContexts;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System.Linq;
using System.Threading.Tasks;
using IdentityServer4;
using IdentityServer4.EntityFramework.Mappers;
using IdentityServer4.Models;
using Microsoft.AspNetCore.Authorization;
using ApiScope = IdentityServer4.EntityFramework.Entities.ApiScope;


namespace Batman.Web.Api.Controllers
{
    [Authorize(IdentityServerConstants.LocalApi.PolicyName)]
    [ApiController]
    [Route("api/[controller]")]
    public class ScopesController : ControllerBase
    {
        IServiceScopeFactory _serviceScopeFactory;

        public ScopesController(IServiceScopeFactory serviceScopeFactory)
        {
            _serviceScopeFactory = serviceScopeFactory;
        }

        public async Task<PagedResponse> Get(int maxResult = 10, int skipCount = 0, bool withIdentityScope = false)
        {
            using (var serviceScope = _serviceScopeFactory.CreateScope())
            {
                var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
                var query = context.ApiScopes.AsNoTracking();
                var data = await query.Skip(skipCount).Take(maxResult).ToListAsync();
                var total = await query.CountAsync();

                if (withIdentityScope)
                {
                    data.Add(new ApiScope {Name  = new IdentityResources.OpenId().Name});
                    data.Add(new ApiScope {Name  = new IdentityResources.Email().Name});
                    data.Add(new ApiScope {Name  = new IdentityResources.Phone().Name});
                    data.Add(new ApiScope {Name  = new IdentityResources.Profile().Name });
                    
                }

                return PagedResponse.New(total, data);
            }
        }

        [HttpPut]
        public async Task<ResponseBase> Put([FromForm] List<ApiScope> scopes)
        {
            using (var serviceScope = _serviceScopeFactory.CreateScope())
            {
                var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
                var scopeNames = scopes.Select(s => s.Name).ToList();

                var ids = scopes.Select(t => t.Id).ToArray();
                var scopeExistings = context.ApiScopes.AsNoTracking().Where(t => ids.Contains(t.Id)).ToList();

                var scopeList = context.ApiScopes.AsNoTracking().Where(t => scopeNames.Contains(t.Name)).ToList();

                var namesExistsing = scopeList.Where(t => scopeExistings.Any(s => s.Name == t.Name && t.Id != s.Id)).Select(t => t.Name).ToArray();

                if (namesExistsing.Length > 0)
                {
                    return new ResponseBase(false, $"范围名称:{string.Join(" ", namesExistsing)} 已经存在，不能重复！");
                }

                foreach (var scopeExisting in scopeExistings)
                {
                    var m = scopes.FirstOrDefault(t => t.Id == scopeExisting.Id);
                    if (m == null) continue;

                    scopeExisting.Name = m.Name;
                    scopeExisting.DisplayName = m.DisplayName;
                    scopeExisting.Description = m.Description;
                    scopeExisting.Enabled = m.Enabled;
                }
                context.ApiScopes.UpdateRange(scopeExistings);

                await context.SaveChangesAsync();

                return new ResponseBase(scopes);
            }
        }

        [HttpPost]
        public async Task<ResponseBase> Post([FromForm] List<ApiScope> scopes)
        {
            using (var serviceScope = _serviceScopeFactory.CreateScope())
            {
                var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
                var scopeNames = scopes.Select(s => s.Name).ToList();
                var scopeNamesExisting = context.ApiScopes.AsNoTracking().Where(t => scopeNames.Contains(t.Name))
                    .Select(t => t.Name).ToList();

                if (scopeNamesExisting.Count > 0)
                {
                    return new ResponseBase(false, $"范围名称:{string.Join(" ", scopeNamesExisting)} 已经存在，不能重复添加！");
                }

                await context.ApiScopes.AddRangeAsync(scopes);

                await context.SaveChangesAsync();

                return new ResponseBase(scopes);
            }
        }

        [HttpDelete]
        public async Task<ResponseBase> Delete([FromForm] List<int> ids)
        {
            using (var serviceScope = _serviceScopeFactory.CreateScope())
            {
                var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
                var scopes = await context.ApiScopes.AsNoTracking().Where(s => ids.Contains(s.Id)).ToListAsync();

                if (scopes.Any(n => n.Name == "IdentityServerApi"))
                {
                    return new ResponseBase(false, "IdentityServerApi作为认证服务器的资源范围，不能被删除!");
                }

                context.ApiScopes.RemoveRange(scopes);
                await context.SaveChangesAsync();
                return new ResponseBase();
            }
        }
    }
}
